﻿#include "yuvoperater.h"

yuvoperater::yuvoperater()
{
    m_bInit = false;
    m_nVideoW = 0;
    m_nVideoH = 0;
    m_nFrameRate = 0;
    m_nCurFrameIndex = 0;
    m_nTotalFrames = 0;
    m_nAvpixelFmt = AV_PIX_FMT_NONE;
    m_bPause = false;
    m_bRunFlag = false;
    imgCtx = nullptr;
    m_pYuvFrame = nullptr;
    m_pRgbFrame = nullptr;
    m_pRgbBuffer = nullptr;    
}

yuvoperater::~yuvoperater()
{

}

int yuvoperater::Init(QString strFile, AVPixelFormat pixelFmt, quint32 nVideoW, quint32 nVideoH, quint16 nFrameRate)
{
    if(m_bInit)
    {
        UnInit();
    }

    if((nVideoW <= 0) || (nVideoH <= 0) )
    {
        return -1;
    }

    m_fileYuv.setFileName(strFile);
    if(!m_fileYuv.open(QIODevice::ReadOnly|QIODevice::Unbuffered))
    {
        return -2;
    }

    m_nVideoW = nVideoW;
    m_nVideoH = nVideoH;
    m_nFrameRate = nFrameRate;
    m_nAvpixelFmt = pixelFmt;
    qint64 nfileLen = m_fileYuv.size();
    m_nTotalFrames = nfileLen/(m_nVideoW*m_nVideoH*3/2);
    m_pYuvFrame = av_frame_alloc();
    m_pRgbFrame = av_frame_alloc();

    int numBytes = avpicture_get_size(AV_PIX_FMT_RGBA, m_nVideoW,m_nVideoH);
    m_pRgbBuffer = new unsigned char[numBytes];
    avpicture_fill((AVPicture*)m_pRgbFrame,m_pRgbBuffer,AV_PIX_FMT_RGBA,m_nVideoW,m_nVideoH);

    imgCtx = sws_getContext(m_nVideoW,m_nVideoH,m_nAvpixelFmt,
                            m_nVideoW,m_nVideoH,AV_PIX_FMT_RGBA,SWS_BILINEAR,0,0,0);
    m_bInit = true;
}

void yuvoperater::UnInit()
{
    m_bInit = false;
    m_nVideoW = 0;
    m_nVideoH = 0;
    m_nFrameRate = 0;
    m_bPause = false;
    m_bRunFlag = false;
    if(m_pYuvFrame)
    {
        av_frame_free(&m_pYuvFrame);
        m_pYuvFrame = nullptr;
    }

    if(m_pRgbFrame)
    {
        av_frame_free(&m_pRgbFrame);
        m_pRgbFrame = NULL;
    }

    if(imgCtx)
    {
        sws_freeContext(imgCtx);
        imgCtx = nullptr;
    }

    if(m_pRgbBuffer)
    {
        delete []m_pRgbBuffer;
        m_pRgbBuffer = nullptr;
    }
}

int yuvoperater::play()
{
    if(!m_bRunFlag)
    {
        m_bRunFlag = true;
        m_bPause = false;
        start();
    }
    else
    {
        m_bPause = false;
    }
}

void yuvoperater::stopPlay()
{
    m_bRunFlag = false;
    m_bPause = false;
    m_fileYuv.seek(0);
}

void yuvoperater::pusePlay()
{
    m_bPause = true;
}

void yuvoperater::preFrame()
{
    if(m_bRunFlag)
    {
        if(!m_bPause)
        {
            m_bPause = true;
        }

        if(m_nCurFrameIndex>0)
        {
            m_nCurFrameIndex--;
            qint64 nFrameLen = m_nVideoW*m_nVideoH*3/2;
            qint64 nPos = m_nCurFrameIndex*nFrameLen;
            m_fileYuv.seek(nPos);
            QByteArray bytesYuv = m_fileYuv.read(nFrameLen);
            sendProcYuvData((uint8_t*)bytesYuv.constData());
        }
    }
}

void yuvoperater::nextFrame()
{
    if(m_bRunFlag)
    {
        if(!m_bPause)
        {
            m_bPause = true;
        }

        if(m_nCurFrameIndex<m_nTotalFrames)
        {
            m_nCurFrameIndex++;
            qint64 nFrameLen = m_nVideoW*m_nVideoH*3/2;
            qint64 nPos = m_nCurFrameIndex*nFrameLen;
            m_fileYuv.seek(nPos);
            QByteArray bytesYuv = m_fileYuv.read(nFrameLen);
            sendProcYuvData((uint8_t*)bytesYuv.constData());
        }
    }
}

void yuvoperater::sendProcYuvData(unsigned char* pYUV)
{
    avpicture_fill((AVPicture*)m_pYuvFrame,pYUV,m_nAvpixelFmt,m_nVideoW,m_nVideoH);
    if (imgCtx != NULL){
        sws_scale(imgCtx,m_pYuvFrame->data,m_pYuvFrame->linesize,
                  0,m_nVideoH,m_pRgbFrame->data,m_pRgbFrame->linesize);

        QImage videoImg((uchar *)m_pRgbBuffer,m_nVideoW,m_nVideoH,QImage::Format_RGB32);
        emit sigOnFrame(videoImg, m_nCurFrameIndex, m_nTotalFrames);
    }
}

void yuvoperater::run()
{
    while(m_bRunFlag)
    {
        if(m_bPause)
        {
            QThread::msleep(1);            
            continue;
        }
        QByteArray bytesYuv = m_fileYuv.read(m_nVideoW*m_nVideoH*3/2);
        sendProcYuvData((uint8_t*)bytesYuv.constData());
        QThread::msleep(40);
        m_nCurFrameIndex++;
    }
}


